package com.zhanglijie.base.threadPool.myThreadPool;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javafx.concurrent.WorkerStateEvent;

/**
 * @author zhanglijie
 * @version 1.0
 * @since 1.1.0 2022/7/5 0005 23:10
 */
public class MyThreadPool  {
    //线程是否关闭
    private volatile boolean isClose = false;
    //定义核心线程数
    private int corePoolSize;
    //最大线程数
    private int maxPoolSize;
    //定义任务 队列
    private static final LinkedList<Runnable> TASK_QUEUE = new LinkedList<>();
    //定义存放工作线程的队列
    private static final List<WorkThread> THREAD_LIST = new ArrayList<>();


    //拒绝策略
    private RejectPolicy rejectPolicy;
    public MyThreadPool(int corePoolSize,int maxThreadNum, RejectPolicy rejectPolicy){
          this.corePoolSize = corePoolSize;
          this.maxPoolSize = maxThreadNum;
          this.rejectPolicy = rejectPolicy;
    }


    private void prestartAllCoreThreads() {
        for (int i = 0; i < corePoolSize; i++) {
            WorkThread workThread = new WorkThread();
            workThread.start();
            THREAD_LIST.add(workThread);//这里不用加同步锁，因为初始化只有main线程在执行
        }
    }
    private void createThread() {
        WorkThread workThread = new WorkThread();
        workThread.start();
        THREAD_LIST.add(workThread);//这里不用加同步锁，因为初始化只有main线程在执行
    }

    private void submit(Runnable task){
        if(isClose) {
            throw new RuntimeException("线程已经关闭了 不能再提交任务执行");
        }
        synchronized (TASK_QUEUE){
            //这里拒绝 简单实现，当任务队列大于最大线程数 执行拒绝策略（真实线程池是阻塞队列满了，并且最大线程数也开了才执行拒绝策略）
            if(TASK_QUEUE.size()  > maxPoolSize){
                System.out.println("当前任务数量"+TASK_QUEUE.size());
                this.rejectPolicy.reject();
            }
            //这里简单实现 直接进任务队列(真实线程池 开始开启核心线程执行任务，核心线程开满了再进队列）
            TASK_QUEUE.addLast(task);
            TASK_QUEUE.notifyAll();
        }
    }

    private enum WorkThreadStatus{
        FREE,BLOCK,RUN,DEAD;
    }

    /**
     * 定义工作线程
     * 获取任务同步，执行可以并行执行
     */
    static  class WorkThread extends Thread{
        private volatile WorkThreadStatus state = WorkThreadStatus.FREE;
        @Override
        public void run(){
            OUTTER:
            while(state != WorkThreadStatus.DEAD){
                Runnable task = null;
                synchronized (TASK_QUEUE) {
                while (TASK_QUEUE.isEmpty()) {
                    if(state != WorkThreadStatus.DEAD) {
                        try {
                            this.state = WorkThreadStatus.BLOCK;
                            TASK_QUEUE.wait();//防止虚假唤醒 上面的判断用while替换if
                        } catch (InterruptedException e) {//这个中断可能是任务队列有任务的时候促发的中断，也可能关闭线程池促发的阻塞
                            //e.printStackTrace();

                            break OUTTER;
                        }
                    }
                }
                task = TASK_QUEUE.remove();
            }
            if (task != null) {
                    this.state = WorkThreadStatus.RUN;
                    task.run();
                    this.state = WorkThreadStatus.FREE;
                }
            }


        }
    }

    /**
     * 拒绝策略
     * 这里拒绝策略提供两个（中止，抛弃）
     * 实际上真实线程池4个 除了上面两个还包括 抛弃最老的任务和调用者自己去执行任务
     */
    public interface RejectPolicy {
        public void reject();
    }

    //中止拒绝策略
    static class AbortRejectPolicy implements RejectPolicy {
        @Override
        public void reject() {
            throw new RuntimeException("中止异常拒绝");
        }
    }
    //抛弃拒绝策略
    static class DiscordPolicy implements RejectPolicy {
        @Override
        public void reject() {
            //什么都不做
        }
    }

    /**
     * 关闭线程池
     * 真实线程池关闭线程有两个（shutdown|shutdownNow)
     * 这里提供shutdown这个友好的中断 ，不提供shutdownNow暴力中断
     */
    private void shutDown() throws InterruptedException {
        //关闭就不能提交任务
        isClose = true;
        //需要等任务队列的任务执行完再去 关闭工作队列
        while (!TASK_QUEUE.isEmpty())  {
            Thread.sleep(300);
        };
        //关闭工作队列
        synchronized (THREAD_LIST){
            isClose = true;
            int size = THREAD_LIST.size();
            while(size >0){
                for (WorkThread workThread : THREAD_LIST) {
                    WorkThreadStatus state = workThread.state;
                    if(state == WorkThreadStatus.BLOCK){
                        workThread.interrupt();
                        workThread.state = WorkThreadStatus.DEAD;
                        size--;//这个size不用考虑是否被并发修改，因为shutdown这个是main线程一个线程执行的
                    }else if(state == WorkThreadStatus.FREE){
                        workThread.state = WorkThreadStatus.DEAD;
                        size--;
                    }else{
                        Thread.sleep(300);//等任务执行下次循环再来判断是否能关闭
                    }
                }
            }
        }
    }







    public static void main(String[] args) throws InterruptedException {
        MyThreadPool myThreadPool = new MyThreadPool(10,20,new AbortRejectPolicy());
        myThreadPool.prestartAllCoreThreads();//类似于ThreadPoolExecutors.prestartAllCoreThreads
        for (int i = 0; i < 20; i++) {
            //提交五十个任务测试
            int finalI = i;
            myThreadPool.submit(()->{
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"===正在执行任务"+ finalI);
            });
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        myThreadPool.shutDown();
    }



}

